{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6735f591",
   "metadata": {},
   "source": [
    "# 多动作多智能体实例-虚拟小镇\n",
    "\n",
    "项目资料：\n",
    "- 1.[metagpt斯坦福虚拟小镇](https://github.com/geekan/MetaGPT/tree/main/metagpt/ext/stanford_town)\n",
    "- 2.[原版斯坦福小镇](https://github.com/joonspk-research/generative_agents?tab=readme-ov-file)\n",
    "- 3.环境运行基于https://github.com/crcresearch/agentic_collab 复现\n",
    "\n",
    "斯坦福小镇中构建了一个虚拟的RPG世界，AI在其中可以自由探索、相互合作、发展友情、举办活动、构建家庭。本节将用Metagpt提供的模块展现斯坦福小镇的互动环境。\n",
    "有几个重要参数如下所示：\n",
    "\n",
    "- idea:将传给小镇第一位居民，模拟由此开始\n",
    "- fork\\_sim\\_code：可以沿用过去的模拟结果，相当于一套居民状况模板，存放在examples/stanford\\_town/storage。也可以用原版斯坦福小镇的[其他模板](https://github.com/joonspk-research/generative_agents/tree/main/environment/frontend_server/storage)\n",
    "- sim\\_code:当前模拟结果保存的文件夹命名，模拟中会不断更新该文件夹\n",
    "- temp\\_storage\\_path:存储模拟的step\n",
    "\n",
    "**小镇环境讲解**\n",
    "\n",
    "小镇用Metagpt的环境模块来实现交互逻辑，让每个角色可以与环境交互，获取观察并更新状态。[具体代码](https://github.com/geekan/MetaGPT/blob/main/metagpt/environment/stanford_town/env_space.py)\n",
    "## 1.（基础级）快速开始尝试：Metagpt斯坦福虚拟小镇模拟使用（jupyter-lab）\n",
    "\n",
    "1. **导入环境相关类并初始化环境**\n",
    "\n",
    "这里选取斯坦福小镇自带的Maze\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e9f9eed4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from metagpt.environment.stanford_town.stanford_town_ext_env import StanfordTownExtEnv\n",
    "from metagpt.environment.stanford_town.env_space import (\n",
    "    EnvAction,\n",
    "    EnvActionType,\n",
    "    EnvObsParams,\n",
    "    EnvObsType,\n",
    ")\n",
    "from metagpt.ext.stanford_town.utils.const.const import MAZE_ASSET_PATH\n",
    "env=StanfordTownExtEnv(maze_asset_path=\"/path/to/MAZE_ASSET_PATH\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a1a630d",
   "metadata": {},
   "source": [
    "2. **观察环境**\n",
    "\n",
    "这里我们选取小镇地图坐标的（72，14），即设定的伊莎贝拉初始位置作为案例，可以通过传给环境观察类型来获取需要的信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d38eae8",
   "metadata": {},
   "outputs": [],
   "source": [
    "obs, _ = env.reset()  # 得到完整观察值\n",
    "path_tiles=env.observe(EnvObsParams(obs_type=EnvObsType.TILE_PATH, coord=(72, 14)))#可以查看当前坐标地址，如可以发现伊莎贝拉初始在自己公寓的主卧床上\n",
    "get_titles=env.observe(EnvObsParams(obs_type=EnvObsType.GET_TITLE, coord=(72, 14)))#可以查看当前坐标的详细观察值\n",
    "nearby_tiles = env.observe(\n",
    "    EnvObsParams(\n",
    "        obs_type=EnvObsType.TILE_NBR, coord=(72, 14), vision_radius=10\n",
    "    )\n",
    ")  # 得到局部观察值，当前位置(200, 300)视野内的其他网格信息"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "976f1964",
   "metadata": {},
   "source": [
    "3. **执行动作**\n",
    "\n",
    "动作说明\n",
    "![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dca9d4997ecd48089227c33822c3768f.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "873fc03e",
   "metadata": {},
   "outputs": [],
   "source": [
    "action = EnvAction(action_type=EnvActionType.RM_TITLE_SUB_EVENT, coord=(72, 14), subject=\"Isabella Rodriguez\")  # 初始化一组动作值，删除指定位置主语为subject的事件,事件event=[\"the Ville:Isabella Rodriguez's apartment:main room:bed\",\"Isabella Rodriguez\",\"is\",\"sleep\"]\n",
    "obs, _, _, _, info = env.step(action)  # 执行动作并得到新的完整观察"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5074fae5",
   "metadata": {},
   "source": [
    "## 2.（进阶级）在vscode中运行搭建斯坦福小镇\n",
    "流程如下：\n",
    "1.配置路径：确保 STORAGE_PATH 和 TEMP_STORAGE_PATH 正确指向原版仓库。\n",
    "2.启动后端：运行 run_demo.py 初始化环境并执行动作。\n",
    "3.启动前端：通过 Django 服务器查看实时模拟。\n",
    "4.验证交互：检查终端日志和前端页面是否同步更新。\n",
    "\n",
    "**2.1环境搭建**\n",
    "**2.1.1前期准备：**\n",
    "1. 安装Python3.9+\n",
    "2. 安装Git\n",
    "3. config配置OpenAI key\n",
    "\n",
    "\n",
    "**2.1.2安装依赖**\n",
    "安装MetaGPT的完整依赖\n",
    "打开项目根目录的requirements.txt文件，将Pillow修改成版本9.5.0，然后安装环境依赖：\n",
    "```bash\n",
    "pip install -r MetaGPT/requirements.txt\n",
    "```\n",
    "安装Django（前端依赖）\n",
    "```bash\n",
    "pip install django\n",
    "```\n",
    "\n",
    "克隆MetaGPT仓库(用于后端运行)\n",
    "```bash\n",
    "git clone https://github.com/geekan/MetaGPT.git\n",
    "\n",
    "```\n",
    "克隆原版斯坦福小镇（Gnenrative Agents）仓库：（用于前端运行）\n",
    "\n",
    "```bash\n",
    "git clone https://github.com/joonspk-research/generative_agents.git\n",
    "\n",
    "```\n",
    "**2.1.3配置路径**\n",
    "在 MetaGPT/examples/stanford_town/const.py 中修改存储路径：\n",
    "```python\n",
    "# 将默认路径替换为你的实际路径\n",
    "STORAGE_PATH = Path(\"/path/to/generative_agents/environment/frontend_server/storage\")\n",
    "TEMP_STORAGE_PATH = Path(\"/path/to/generative_agents/environment/frontend_server/temp_storage\")\n",
    "```\n",
    "**关键参数说明**\n",
    "maze_asset_path：确保与 generative_agents 的 maze_asset_path 一致。\n",
    "temp_storage_path：确保与 generative_agents 的临时存储路径一致。\n",
    "\n",
    "fork_sim_code：使用预存的模拟模板（如 base_the_ville_isabella_maria_klaus）。\n",
    "\n",
    "sim_code：自定义当前模拟结果的保存目录\n",
    "**2.2后端服务代码**\n",
    "在 MetaGPT/examples/stanford_town 目录下创建 run_demo.py：\n",
    "```python\n",
    "import asyncio\n",
    "from metagpt.environment.stanford_town.stanford_town_ext_env import StanfordTownExtEnv\n",
    "from metagpt.environment.stanford_town.env_space import (\n",
    "    EnvAction,\n",
    "    EnvActionType,\n",
    "    EnvObsParams,\n",
    "    EnvObsType,\n",
    ")\n",
    "from metagpt.ext.stanford_town.utils.const.const import MAZE_ASSET_PATH\n",
    "\n",
    "async def main():\n",
    "    # 初始化环境\n",
    "    env = StanfordTownExtEnv(\n",
    "        maze_asset_path=MAZE_ASSET_PATH,\n",
    "        temp_storage_path=\"temp_storage\"  # 确保与前端路径一致\n",
    "    )\n",
    "\n",
    "    # 重置环境，获取初始观察值\n",
    "    obs, _ = await env.reset()\n",
    "    print(\"初始观察值:\", obs)\n",
    "\n",
    "    # 观察特定坐标（例如伊莎贝拉的初始位置）\n",
    "    coord = (72, 14)\n",
    "    path_tiles = await env.observe(EnvObsParams(\n",
    "        obs_type=EnvObsType.TILE_PATH,\n",
    "        coord=coord\n",
    "    ))\n",
    "    print(f\"坐标 {coord} 的路径信息:\", path_tiles)\n",
    "\n",
    "    # 获取附近视野信息\n",
    "    nearby_tiles = await env.observe(EnvObsParams(\n",
    "        obs_type=EnvObsType.TILE_NBR,\n",
    "        coord=coord,\n",
    "        vision_radius=10\n",
    "    ))\n",
    "    print(f\"附近视野信息:\", nearby_tiles)\n",
    "\n",
    "    # 执行动作：删除事件\n",
    "    action = EnvAction(\n",
    "        action_type=EnvActionType.RM_TITLE_SUB_EVENT,\n",
    "        coord=coord,\n",
    "        subject=\"Isabella Rodriguez\"\n",
    "    )\n",
    "    new_obs, _, _, _, _ = await env.step(action)\n",
    "    print(\"执行动作后的新观察值:\", new_obs)\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    asyncio.run(main())\n",
    "```\n",
    "**2.3启动服务**\n",
    "**2.3.1启动后端服务**\n",
    "```bash\n",
    "cd MetaGPT/examples/stanford_town\n",
    "python run_demo.py --temp_storage_path /path/to/generative_agents/temp_storage\n",
    "```\n",
    "**2.3.2启动前端服务**\n",
    "保持后端不关闭，另开一个终端，启动前端服务：\n",
    "```bash\n",
    "cd generative_agents/environment/frontend_server\n",
    "python manage.py runserver #启动Django服务器\n",
    "```\n",
    "**2.3.3访问前端**\n",
    "在浏览器中访问 http://localhost:8000/simulator_home 即可看到斯坦福小镇的前端界面。\n",
    "**2.4运行结果：**\n",
    "先启动后端再前端\n",
    "**2.4.1后端运行结果：**\n",
    "```\n",
    "初始观察值: { ... }\n",
    "坐标 (72, 14) 的路径信息: { ... }\n",
    "附近视野信息: { ... }\n",
    "执行动作后的新观察值: { ... }\n",
    "\n",
    "```\n",
    "**2.4.2前端运行结果：**\n",
    "前端页面：显示虚拟小镇地图和角色动态。\n",
    "\n",
    "如果前端无数据：确保 temp_storage 目录中有生成的步骤文件，重启后端和前端服务。\n",
    "\n",
    "如果出现路径错误：\n",
    "1.检查 const.py 和命令行参数中的路径是否为绝对路径\n",
    "2.确保 temp_storage 目录有读写权限"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
